/*
 * Copyright (c) 2000-2012 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */
/* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
/*
 * Copyright (c) 1990, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)filedesc.h	8.1 (Berkeley) 6/2/93
 */

#ifndef _SYS_FILEDESC_H_
#define _SYS_FILEDESC_H_

#include <sys/appleapiopts.h>

/*
 * This structure is used for the management of descriptors.  It may be
 * shared by multiple processes.
 *
 * A process is initially started out with NDFILE descriptors [XXXstored within
 * this structureXXX], selected to be enough for typical applications based on
 * the historical limit of 20 open files (and the usage of descriptors by
 * shells).  If these descriptors are exhausted, a larger descriptor table
 * may be allocated, up to a process' resource limit; [XXXthe internal arrays
 * are then unusedXXX].  The initial expansion is set to NDEXTENT; each time
 * it runs out, it is doubled until the resource limit is reached. NDEXTENT
 * should be selected to be the biggest multiple of OFILESIZE (see below)
 * that will fit in a power-of-two sized piece of memory.
 */
#define NDFILE          25              /* 125 bytes */
#define NDEXTENT        50              /* 250 bytes in 256-byte alloc. */

#ifdef BSD_KERNEL_PRIVATE

#include <kern/locks.h>

struct klist;
struct kqwllist;

struct filedesc {
	struct  fileproc **fd_ofiles;   /* file structures for open files */
	lck_mtx_t fd_kqhashlock;        /* lock for dynamic kqueue hash */
	u_long  fd_kqhashmask;          /* size of dynamic kqueue hash */
	struct  kqwllist *fd_kqhash;    /* hash table for dynamic kqueues */
	struct  kqworkq *fd_wqkqueue;   /* the workq kqueue */
	char    *fd_ofileflags;         /* per-process open file flags */
	struct  vnode *fd_cdir;         /* current directory */
	struct  vnode *fd_rdir;         /* root directory */
	int     fd_nfiles;              /* number of open files allocated */
	int     fd_lastfile;            /* high-water mark of fd_ofiles */
	int     fd_freefile;            /* approx. next free file */
	mode_t  fd_cmask;               /* mask for file creation */
	int     fd_flags;
	int     fd_knlistsize;          /* size of knlist */
	struct  klist *fd_knlist;       /* list of attached knotes */
	u_long  fd_knhashmask;          /* size of knhash */
	struct  klist *fd_knhash;       /* hash table for attached knotes */
	lck_mtx_t fd_knhashlock;        /* lock for hash table for attached knotes */
};

/*
 * definitions for fd_flags;
 */
#define FD_CHROOT       0x01    /* process was chrooted... keep track even */
                                /* if we're force unmounted and unable to */
                                /* take a vnode_ref on fd_rdir during a fork */

#define FD_WORKLOOP     0x02    /* process has created a kqworkloop that */
                                /* requires manual cleanup on exit */

/*
 * Per-process open flags.
 */
#define UF_EXCLOSE      0x01            /* auto-close on exec */
#define UF_FORKCLOSE    0x02            /* auto-close on fork */
#define UF_RESERVED     0x04            /* open pending / in progress */
#define UF_CLOSING      0x08            /* close in progress */
#define UF_RESVWAIT     0x10            /* close in progress */
#define UF_INHERIT      0x20            /* "inherit-on-exec" */

#define UF_VALID_FLAGS  \
	(UF_EXCLOSE | UF_FORKCLOSE | UF_RESERVED | UF_CLOSING |\
	UF_RESVWAIT | UF_INHERIT)

/*
 * Storage required per open file descriptor.
 */
#define OFILESIZE (sizeof(struct file *) + sizeof(char))

/*!
 * @struct fdt_iterator
 *
 * @brief
 * Type used to iterate a file descriptor table.
 */
struct fdt_iterator {
	int              fdti_fd;
	struct fileproc *fdti_fp;
};

/*!
 * @function fdt_next
 *
 * @brief
 * Seek the iterator forward.
 *
 * @param p
 * The process for which the file descriptor table is being iterated.
 *
 * @param fd
 * The current file file descriptor to scan from (exclusive).
 *
 * @param only_settled
 * When true, only fileprocs with @c UF_RESERVED set are returned.
 * If false, fileprocs that are in flux (@c UF_RESERVED is set) are returned.
 *
 * @returns
 * The next iterator position.
 * If @c fdti_fp is NULL, the iteration is done.
 */
extern struct fdt_iterator
fdt_next(proc_t p, int fd, bool only_settled);

/*!
 * @function fdt_next
 *
 * @brief
 * Seek the iterator backwards.
 *
 * @param p
 * The process for which the file descriptor table is being iterated.
 *
 * @param fd
 * The current file file descriptor to scan from (exclusive).
 *
 * @param only_settled
 * When true, only fileprocs with @c UF_RESERVED set are returned.
 * If false, fileprocs that are in flux (@c UF_RESERVED is set) are returned.
 *
 * @returns
 * The next iterator position.
 * If @c fdti_fp is NULL, the iteration is done.
 */
extern struct fdt_iterator
fdt_prev(proc_t p, int fd, bool only_settled);

/*!
 * @def fdt_foreach
 *
 * @brief
 * Convenience macro around @c fdt_next() to enumerates fileprocs in a process
 * file descriptor table.
 *
 * @param fp
 * The iteration variable.
 *
 * @param p
 * The process for which the file descriptor table is being iterated.
 */
#define fdt_foreach(fp, p) \
	for (struct fdt_iterator __fdt_it = fdt_next(p, -1, true); \
	    ((fp) = __fdt_it.fdti_fp); \
	    __fdt_it = fdt_next(p, __fdt_it.fdti_fd, true))

/*!
 * @def fdt_foreach_fd
 *
 * @brief
 * When in an @c fdt_foreach() loop, return the current file descriptor
 * being inspected.
 */
#define fdt_foreach_fd()  __fdt_it.fdti_fd

/*
 * Kernel global variables and routines.
 */
extern int      dupfdopen(struct filedesc *fdp,
    int indx, int dfd, int mode, int error);
extern int      fdalloc(proc_t p, int want, int *result);
extern int      fdavail(proc_t p, int n);
#define         fdfile(p, fd)                                   \
	                (&(p)->p_fd->fd_ofiles[(fd)])
#define         fdflags(p, fd)                                  \
	                (&(p)->p_fd->fd_ofileflags[(fd)])

/*
 * Accesor macros for fd flags
 */
#define FDFLAGS_GET(p, fd) (*fdflags(p, fd) & (UF_EXCLOSE|UF_FORKCLOSE))
#define FDFLAGS_SET(p, fd, bits) \
	   (*fdflags(p, fd) |= ((bits) & (UF_EXCLOSE|UF_FORKCLOSE)))
#define FDFLAGS_CLR(p, fd, bits) \
	   (*fdflags(p, fd) &= ~((bits) & (UF_EXCLOSE|UF_FORKCLOSE)))

extern int      falloc(proc_t p, struct fileproc **resultfp, int *resultfd, vfs_context_t ctx);

typedef struct fileproc *(*fp_allocfn_t)(void *);
extern int      falloc_withalloc(proc_t p, struct fileproc **resultfp,
    int *resultfd, vfs_context_t ctx,
    fp_allocfn_t fp_zalloc, void *crarg);

extern struct   filedesc *fdcopy(proc_t p, struct vnode *uth_cdir);
extern void     fdfree(proc_t p);
extern void     fdexec(proc_t p, short flags, int self_exec);

#endif /* BSD_KERNEL_PRIVATE */

#endif /* !_SYS_FILEDESC_H_ */
